昨天介紹了 Content Security Policy 跟 HTTP Strict Transport Security 兩個 HTTP header,今天緊接著要來介紹另外兩個 X 開頭的 X-Content-Type-Options 跟 X-Frame-Options,像這類 X 開頭的 HTTP header 一開始都是要用來實驗看看是不是真的能增加安全性,後來因為逐漸普及也不能再隨便亂改,便決定維持這個名字。所以千萬不要看到他是 X 開頭就覺得他不是標準的 header 哦,他們沒改名只是為了向已經寫好的網站相容而已~
在正式講這個 header 之前,得先來談談什麼是 content sniffing:一般來說瀏覽器會透過 Content-Type 來判斷請求到的資源是什麼類型,像透過 <script src="script.js">
拿到的 Content-Type 一般都是 text/javascript
,因此瀏覽器看到之後就會拿來執行
但有些網站(尤其是十幾二十年前的舊網站)在開發時並沒有把 Content-Type 設好,導致某些 JS 檔的 Content-Type 是 text/plain
,也就是純文字檔。為了讓這些網站可以順利運作,瀏覽器除了參考 Content-Type 之外,也會做 content sniffing 從檔案內容分析是什麼類型,如果分析出是 JS 那就會拿去執行,這樣舊網站才不會壞掉
但 sniffing 這個動作看似貼心,卻也是一個弱點。譬如說有些網站允許使用者上傳檔案,那攻擊者就可以惡意上傳一些有 JS 特徵的 JPG 檔(這些圖片會被瀏覽器判斷成腳本)。接著想辦法讓這張圖片被載入到前端來,導致裡面的惡意腳本被執行,造成 XSS 攻擊
為了防止瀏覽器在那邊亂猜檔案的 Content-Type 是什麼(而且麻煩的是每個瀏覽器猜的方式還不太一樣),我們要在 headers 裡面加上 X-Content-Type-Options: nosniff
告訴瀏覽器直接用 header 裡面提供的 Content-Type 就好,不要在那邊瞎猜,如此一來就不會再有純文字、圖片被判斷成腳本這種事
但也因為加了 nosniff,所以務必要注意各種資源的 Content-Type 有沒有設定好,因為瀏覽器不會幫你猜,如果你真的把 JS、CSS 的 Content-Type 設錯,那瀏覽器就不會把它跑起來,網站看起來也就怪怪的
平常在寫網頁時,若是想把其他網頁的內容拿過來用(下圖),可以用 <iframe src="https://website.com">
把他嵌入進來;反之,若是別人想把我做的網站嵌入到他的網站裡面也是可以的
那這樣會有什麼資安疑慮呢?萬一有個壞壞網站,他透過 iframe 把氣象局網頁嵌入進去後,用 CSS 把那個 iframe 調成透明的,然後在透明的 iframe 背後放一些按鈕(下圖)。那使用者在壞壞網站上點擊我很帥、我帥爆時,就會不小心點到氣象局的網站,這種攻擊就稱作 Clickjacking
如果點到的只是氣象局網站那不會怎麼樣,反正怎麼點也就是那樣。但萬一被嵌入的是某銀行的網站呢?那使用者可能就會被精心設計的按鈕給騙到,在無意識的情況下就按了 iframe 裡面的轉帳、提款等等按鈕
為了要避免這類問題,最好的方法就是加上 X-Frame-Options: deny
這個 header,意思是告訴瀏覽器說我這個網站不想被嵌入(為了安全起來大部分的銀行都會加這個 header)
所以當我想在自己的網站上把玉山銀行的頁面嵌入進來時,瀏覽器就會噴出「ebank.esunbank.com.tw
不允許在被別的網站嵌入」的錯誤。因為玉山銀行的頁面根本不允許被嵌入,也就避免了基於 iframe 的 Clickjacking 攻擊
今天又介紹了兩個比較冷門的 HTTP Header,雖然除了這四個之外其實還有 X-XSS-Protection
、Expect-CT
、Public-Key-Pins
、Feature-Policy
等等很多跟安全性有關的 HTTP header,但因為有些效果沒那麼大、有些則是已經被宣佈棄用了,所以這邊就暫且不提,有興趣可以自己到 Owasp Secure Headers 上面看看~
如果對於今天的內容有什麼問題的話歡迎在下方留言,沒有的話明天就要來說說怎麼在 Node/Go 寫的 API server 把這些 header 用上去了~